<?php

/*  This collection of functions (libary) is licensed under GPL2.
    See LICENSE or www.gnu.org for more details.

    Implementations for ahjos. An ahjo is an object that creates script
    code for one field feature. The script is dynamic. That is, It is
    always different depending on the form, the state of the form and
    the features defined for the fields on the form.

    Some form/field features need hardcoding. This is implemented by ahjos.
    Typically ahjo implements one special data structure that is used from
    the script code (e.g. JavaScript).

    dzScripSeppo uses ahjos as helper classes. It uses ahjos through ahjo
    list that is defined here also. See below. All ahjos should be listed
    there.

    Below is a class definition called dzBaseAhjo. Use it as a base for your
    own ahjos. Because PHP does not allow virtual classes just copy the base
    class, rename it and implement the four methods. See the instructions
    below.

    HOW TO ADD AN AHJO?

    1) copy the base class
    2) Rename the class. Remember to rename the constructor too.
    3) Implement the four required methods
    4) Insert the new ahjo into ahjolist

    @author Henri Ranki & Jyry Kuukkanen

    $Id: dzahjo.php,v 1.13 2005/11/02 19:35:25 jyry Exp $
 */

include_once("sodebug.php");
include_once("sostring.php");
include_once("soset.php");
include_once("soconst.php");

include_once("dzconst.php");
include_once("dzstonga.php");
include_once("dzmenu.php");
include_once("dztemplate.php");


/** This is called to get a list of ahjos as well as insert your own ahjos
 *  here into list.
 *  @param dzTemplate $__Template Reference to used template
 *  @return array Array of ahjos
 */
function getAhjoList(&$Template) {
    soDebug("dzAhjo: Create ahjo list", SOD_DET);

    /* Check if menu has been created before. If not, then create it.
     * The serialisation is required to fool php not to go mad with
     * session handling. */
    if ($Template->_Menu == NULL) {
        $Template->_Menu = serialize(new dzAhjoMenu($Template));
    }; // if

    /* Create array of used ahjos. Add your own ahjos here too */
    $ahjo_list = array(
        new dzAhjoStonga($Template), /* Create stonga */
        unserialize($Template->_Menu),
        new dzAhjoRoamMap($Template),       /* Roam map */
        new dzAhjoCalculate($Template),     /* Calculate fields */
        new dzAhjoTypeCheck($Template),     /* Type check */
        new dzAhjoNewLine($Template),       /* New line event */
        new dzAhjoFetch($Template),         /* Fetch event */
        new dzAhjoValidate($Template),      /* Validy check */
#        new dzAhjoReadOnly($Template),      /* Read only field list */
        new dzAhjoPostChange($Template)     /* Post change event */
        );

    soDebug("dzAhjo: Created ahjo list with ".count($ahjo_list).
            " ahjos", SOD_DET);

    return $ahjo_list;
}; // getAhjoList


/** Base class. *Not* to used directly but through inheritence only.
 *  Use this class as base when creating feature ahjos. Copy this and
 *  implement the methods.
 *
 *  Ahjos is used to create custom features. That is features that needs
 *  Hardcoded JavaScript. Typically these pieces of scripts are kind of
 *  Data structures needed to implement  the feature.
 *
 *  See the file header for further information.
 *  @var dzTemplate $__Template Form information. Includes lots of field information too 
 */
class dzBaseAhjo {
    var $__Template = NULL;

    /**  NOTE! When copying this class, update the name of the constructor to
     *   correspond the new class name.
     *   @param dzTemplate $__Template Template object used by Ahjo.
     */
    function dzBaseAhjo(&$Template) {
        soDebug("dzAhjo: Create", SOD_DET);
        $this->setTemplate($Template);
    } // constructor


    /** Sets a new template for Ahjo.
     *  @param dzTemplate $__Template Template object used by Ahjo.
     */
    function setTemplate(&$Template) {
        soDebug("dzAhjo->setTemplate", SOD_DET);
        $this->__Template = &$Template;
    } // constructor


    /** Check if this field is needs this ahjo.
     *  Inspects the field properties and decides whether this ahjo is needed
     *  to implement the fields features.
     *  @param dzSourceEntity $Entity The field data to check
     *  @return bool True if the field has the feature that is produced by this ahjo.
     */
    function isRequiredField($Entity) {
        /* Implementation here */
    } // isRequiredField


    /** Add field to ahjo
     *  @param dzSourceEntity $Entity The field data to check
     *  @param string $TagName Column name
     *  @param string $FieldName The widget name on the form
     *  @param any $Value The fields value
     *  @return bool True on success false on error
     */
    function addField($Entity, $TagName, $FieldName, $Value) {
        if ($this->isRequiredField($Entity)) {
            /* Implementation here */
            $result = true;
        } else {
            $result = false;
        } // if

        return $result;
    } // addField


    /** Get the script code
     *  Get the script code that is needed to implement the functionality this
     *  ahjo is responsible for.
     *  @return The script code
     */
    function getCode() {
        /* Implementation here */
    } // getCode


    /** Get static script features
     * Get the other static script features that is needed to implement
     * the functionality this ahjo is responsible for
     * @return array/string  List of the required features names
     */
    function getScriptFeatures() {
        /* Implementation here */
    } // getScriptFeatures

} //  dzBaseAhjo


/******************************************************************************
 *
 *                      REAL AHJO IMPLEMENTATIONS
 *
 *****************************************************************************/


/** Ahjo that produces the type check information
 *  @var dzTemplate $__Template Form information. Includes lots of field information, too.
 *  @var object soSet $__TypeCheckInfo Type check info for the fields
 */
class dzAhjoTypeCheck extends dzBaseAhjo {
    var $__Template = NULL;
    var $__TypeCheckInfo;

    /** Constructor
     *  @param dzTemplate $__Template Template object used by Ahjo.
     */
    function dzAhjoTypeCheck(&$Template) {
        soDebug("dzAhjo: Create ahjo dzAhjoTypeCheck",SOD_DET);
        $this->setTemplate($Template);
        $this->__TypeCheckInfo = new soSet();
    } // constructor


    /** Check if this field is needs this ahjo.
     *  Inspects the field properties and decides whether this ahjo is needed
     *  to implement the fields features.
     *  @param dzSourceEntity $Entity The field data to check
     *  @return bool True if the field has the feature that is produced by this ahjo.
     */
    function isRequiredField($Entity) {
        /* All fields have type check info so return true for all */
        return true;
    } // isRequiredField


    /** Add field to ahjo
     *  @param dzSourceEntity $Entity The field data to check
     *  @param string $TagName Column name
     *  @param string $FieldName The widget name on the form
     *  @param any $Value The fields value
     *  @return bool True on success false on error
     */
    function addField($Entity, $TagName, $FieldName, $Value) {
        if ($this->isRequiredField($Entity)) {

            /* Collect the type check info */
            $type = $this->__Template->getColProperty(
                $Entity->Name, DZCPT_STRUCT, DZCP_TYPE);
            if (in_array($type,
                         array(SODT_DATE, SODT_TIME, SODT_DATETIME, "dt"))) {
                $date_format = ";".soSubStr(dzGetIniItem(DZIS_GENERAL,
                                                         DZID_DATE),
                                        0, 1);
                /* Store the type and date stamp format of this column. */
                $this->__TypeCheckInfo->addItem($TagName,
                                                $type.$date_format);
            } else {
                $auto_adjust = ($this->__Template->getColProperty(
                    $Entity->Name, DZCPT_STRUCT,
                    DZCP_AUTOADJUST)) ? ";A" : "";
                $ranges = $this->__Template->getColProperty(
                    $Entity->Name, DZCPT_STRUCT, DZCP_RANGE);
                if (!is_array($ranges)) $ranges = array();
                $range_str = "";
                foreach ($ranges as $range) {
                    $range_str = soJoinStr($range_str,
                                           "+",
                                           $range["min"].",".$range["max"],
                                           1);
                }; // foreach

                /* Store type and autoadjust info for this column. */
                $range_str = ";".$range_str;
                $this->__TypeCheckInfo->addItem($TagName,
                                                $type.$range_str.$auto_adjust);
            } // if

            $result = true;
        } else {
            $result = false;
        } // if

        return $result;
    } // addField


    /** Get the script code
     *  Get the script code that is needed to implement the functionality this
     *  ahjo is responsible for.
     *  @return The script code
     */
    function getCode() {
        $result = "";
        $mode = $this->__Template->getViewData(DZ_VI_MODE);

        if ($mode != DZM_QUERY) {
            $field_list = $this->__TypeCheckInfo->getAsArray();
            while (list($field_name, $info) = each($field_list)) {
                $result .= "dzType_".$field_name."=\"".$info."\";\n";
            } // while
        } // if

        return $result;
    } // getCode


    /** Get static script features
     *  Get the other static script features that is needed to implement
     *  the functionality this ahjo is responsible for
     *  @return string Space limited list of the features names
     */
    function getScriptFeatures() {
        /* Type check scripts are included by default */
        return array();
    } // getScriptFeatures
} //  dzAhjoTypeCheck



/** Ahjo that produces the post change event information
 *  @param dzTemplate $__Template Reference to used template
 */
class dzAhjoPostChange extends dzBaseAhjo {
    var $__Template = NULL; 
    var $__FieldInfo;   /**soSet/str type check info for the fields */

    /**
     */
    function dzAhjoPostChange($Template) {
        soDebug("dzAhjo: Create ahjo dzAhjoPostChange",SOD_DET);
        $this->setTemplate($Template);
        $this->__FieldInfo = new soSet();
    } // constructor


    /** Check if this field is needs this ahjo.
     *  Inspects the field properties and decides whether this ahjo is needed
     *  to implement the fields features.
     *  >$Entity:dzSourceEntity The field data to check
     *  <:bool true if the field has the feature that is produced by this ahjo.
     */
    function isRequiredField($Entity) {
        return soGetBool(
            $this->__Template->getColProperty($Entity->Name, 
                                              DZCPT_CONTROL,
                                              DZCP_AFTER_CHANGE));
    } // isRequiredField


    /** Add field to ahjo
     *
     *  >$Entity:dzSourceEntity The field data to check
     *  >$TagName:str   Column name
     *  >$FieldName:str   The widget name on the form
     *  >$Value:any   The fields value
     *  <:bool  true on success false on error
     */
    function addField($Entity, $TagName, $FieldName, $Value) {
        if ($this->isRequiredField($Entity)) {
            $post_change = $this->__Template->getColProperty(
                $Entity->Name, DZCPT_CONTROL, DZCP_AFTER_CHANGE);
            /* Is rpc add the coordinates of the function */
            if (soSubStr($post_change, 0, 4) == "rpc:") {
                $post_change = completeRpcInfo($post_change);
            } // if
            $this->__FieldInfo->addItem($TagName, $post_change);
            $result = true;
        } else {
            $result = false;
        } // if

        return $result;
    } // addField


    /** Get the script code
     *  Get the script code that is needed to implement the functionality this
     *  ahjo is responsible for.
     *  <: the script code
     */
    function getCode() {
        $result = "";
        $field_list = $this->__FieldInfo->getAsArray();
        while (list($field_name, $function) = each ($field_list)) {
            $result .= "dzAC_".$field_name."=\"".$function."\";\n";
        } // while

        return $result;
    } // getCode


    /** Get static script features
     * Get the other static script features that is needed to implement
     * the functionality this ahjo is responsible for
     * <:str space limited list of the features names
     */
    function getScriptFeatures() {
        return array("after_change", "post_process",
                     "general_post_process", "rcall");
    } // getScriptFeatures
} //  dzAhjoPostChange


/** Ahjo that produces the stonga
 *  @param dzTemplate $__Template Reference to used template
 */
class dzAhjoStonga extends dzBaseAhjo {
    var $__Template = NULL;


    /**  NOTE! When copying this class, update the name of the constructor to
     *   correspond the new class name.
     *   @param dzTemplate $__Template Template object used by Ahjo.
     */
    function dzAhjoStonga(&$Template) {
        soDebug("dzAhjo: Create ahjo dzAhjoStonga",SOD_DET);
        $this->setTemplate($Template);
    } // constructor


    /** Check if this field is needs this ahjo.
     *  Inspects the field properties and decides whether this ahjo is needed
     *  to implement the fields features.
     *  >$Entity:dzSourceEntity The field data to check
     *  <:bool true if the field has the feature that is produced by this ahjo.
     */
    function isRequiredField($Entity) {
        /* No fields are needed by this ahjo */
        return false;
    } // isRequiredField


    /** Add field to ahjo
     *
     *  >$Entity:dzSourceEntity The field data to check
     *  >$TagName:str   Column name
     *  >$FieldName:str   The widget name on the form
     *  >$Value:any   The fields value
     *  <:bool  true on success false on error
     */
    function addField($Entity, $TagName, $FieldName, $Value) {
        if ($this->isRequiredField($Entity)) {
            /* No field information needed */
            $result = true;
        } else {
            $result = false;
        } // if

        return $result;
    } // addField


    /** Get the script code
     *  Get the script code that is needed to implement the functionality this
     *  ahjo is responsible for.
     *  <: the script code
     */
    function getCode() {
        return dzMakeStonga($this->__Template);
    } // getCode


    /** Get static script features
     * Get the other static script features that is needed to implement
     * the functionality this ahjo is responsible for
     * <:array/str  List of the required features names
     */
    function getScriptFeatures() {
        return array();
    } // getScriptFeatures

} //  dzAhjoStonga


/** Ahjo that produces the menu
 *  @var dzTemplate $__Template Form information. Includes lots of field
 *      information too
 *  @var string $__MenuScript Menu script to be sent to the client.
 *  @package dzAhjo
 */
class dzAhjoMenu extends dzBaseAhjo {
    var $__Template = NULL;
    var $__MenuScript;


    /**  NOTE! When copying this class, update the name of the constructor to
     *   correspond the new class name.
     *   @param dzTemplate $__Template Template object used by Ahjo.
     */
    function dzAhjoMenu(&$Template) {
        soDebug("dzAhjo: Create ahjo dzAhjoMenu",SOD_DET);
        $this->setTemplate($Template);
        $suspend = $Template->ScriptFeatureSpool->getAttrib(DZSA_SUSPEND);
        $menu = new dzMenu();
        if (DZMP_STYLE == DZMP_DROPDOWN) {
            $this->__MenuScript =
            dzGetMenu($suspend,
                           $Template->SessionInfo->UserID,
                           $Template->SessionInfo->Groups,
                           $Template->SessionInfo->UserLevel,
                           "",
                           $Template->SessionInfo->Lang);
        } else {
            $this->__MenuScript =
            $menu->getMenu($suspend,
                           $Template->SessionInfo->UserID,
                           $Template->SessionInfo->Groups,
                           $Template->SessionInfo->UserLevel,
                           "",
                           $Template->SessionInfo->Lang);
        }; // else if
    } // constructor


    /** Check if this field is needs this ahjo.
     *  Inspects the field properties and decides whether this ahjo is needed
     *  to implement the fields features.
     *  >$Entity:dzSourceEntity The field data to check
     *  <:bool true if the field has the feature that is produced by this ahjo.
     */
    function isRequiredField($Entity) {
        /* No fields are needed by this ahjo */
        return false;
    } // isRequiredField


    /** Add field to ahjo
     *
     *  >$Entity:dzSourceEntity The field data to check
     *  >$TagName:str   Column name
     *  >$FieldName:str   The widget name on the form
     *  >$Value:any   The fields value
     *  <:bool  true on success false on error
     */
    function addField($Entity, $TagName, $FieldName, $Value) {
        if ($this->isRequiredField($Entity)) {
            /* No field information needed */
            $result = true;
        } else {
            $result = false;
        } // if

        return $result;
    } // addField


    /** Get the script code
     *  Get the script code that is needed to implement the functionality this
     *  ahjo is responsible for.
     *  <: the script code
     */
    function getCode() {
        return $this->__MenuScript;
    } // getCode


    /** Get static script features
     * Get the other static script features that is needed to implement
     * the functionality this ahjo is responsible for
     * <:array/str  List of the required features names
     */
    function getScriptFeatures() {
        return array();
    } // getScriptFeatures

} //  dzAhjoMenu


/** Ahjo that produces the roam map
 *  @param dzTemplate $__Template Reference to used template
 */
class dzAhjoRoamMap extends dzBaseAhjo {
    var $__Template = NULL;
    var $__Widgets;         /**array/str List of widget names */


    /**  NOTE! When copying this class, update the name of the constructor to
     *   correspond the new class name.
     *   @param dzTemplate $__Template Template object used by Ahjo.
     */
    function dzAhjoRoamMap(&$Template) {
        soDebug("dzAhjo: Create ahjo dzAhjoRoamMap",SOD_DET);
        $this->setTemplate($Template);
        $this->__Widgets = array();
    } // constructor


    /** Check if this field is needs this ahjo.
     *  Inspects the field properties and decides whether this ahjo is needed
     *  to implement the fields features.
     *  >$Entity:dzSourceEntity The field data to check
     *  <:bool true if the field has the feature that is produced by this ahjo.
     */
    function isRequiredField($Entity) {
        /* accept all the given fields */
        return true;
    } // isRequiredField


    /** Add field to ahjo
     *
     *  >$Entity:dzSourceEntity The field data to check
     *  >$TagName:str   Column name
     *  >$FieldName:str   The widget name on the form
     *  >$Value:any   The fields value
     *  <:bool  true on success false on error
     */
    function addField($Entity, $TagName, $FieldName, $Value) {
        if ($this->isRequiredField($Entity)) {
            $this->__Widgets[] = $FieldName;
            $result = true;
        } else {
            $result = false;
        } // if

        return $result;
    } // addField


    /** Get the script code
     *  Get the script code that is needed to implement the functionality this
     *  ahjo is responsible for.
     *  <: the script code
     */
    function getCode() {
        $result = "";
        $row = 0; $s="";

        foreach ($this->__Widgets as $widget_name) {
            /* Extract the row number of the next component */
            $newRow = soExtractVal($widget_name, "_", 3);

            /* If the row has changed start a new row in the
               roaming map as well */
            if ($newRow != $row) {
                /* Make the row information. Et the end there is an end
                  of row row marker '' */
                $tmp = "CompMap[$row] = [$s,''];";
                $result = soJoinStr($result, "\n", $tmp, 1);
                $row = $newRow; $s = "";
            } // if
            $s = soJoinStr($s, ",", "'".$widget_name."'", 1);
        } // foreach
        if ($row >0 ) {
            $tmp = "CompMap[$row] = [$s, ''];";
            $result = soJoinStr($result, "\n", $tmp, 1);
            $row++;
        }

        /* Add map end marker */
        $tmp = "CompMap[".$row."] = ['']; //this marks the end of the array";
        $result = soJoinStr($result, "\n", $tmp, 1);

        /* Insert map size in the beginning of the produced script */
        $row++;
        $tmp = "CompMap = new Array(".$row.");";
        $result = soJoinStr($result, "\n", $tmp, 0);

        return $result;
    } // getCode


    /** Get static script features
     * Get the other static script features that is needed to implement
     * the functionality this ahjo is responsible for
     * <:array/str  List of the required features names
     */
    function getScriptFeatures() {
        return array();
    } // getScriptFeatures

} //  dzAhjoRoamMap



/** Forge that produces the data structures for calculate fields
 *  @var object dzTemplate $__Template Form information. Includes tons of
 *  field information too
 *  @var array/string $__Formulas Formula definitions
 *  @var array/string $__Formats Format definitions
 *  @var object soSet/string $__FieldDeps Field dependencies
 */
class dzAhjoCalculate extends dzBaseAhjo {
    var $__Template = NULL;
    var $__Formulas;
    var $__Formats;
    var $__FieldDeps;


    /*  NOTE! When copying this class, in order to handle different type
     *  of Ahjo function/purpose, update the name of the constructor to
     *  correspond the new class name.
     *  @param object dzTemplate Form template object.
     */
    function dzAhjoCalculate(&$Template) {
        soDebug("dzAhjo: Create ahjo dzAhjoCalculate",SOD_DET);
        $this->setTemplate($Template);
        $this->__Formulas = array();
        $this->__Formats = array();
        $this->__FieldDeps = new soSet();
    } // constructor


    /** Check if this field is needs this ahjo.
     *  Inspects the field properties and decides whether this ahjo is needed
     *  to implement the fields features.
     *  @param object dzSourceEntity $Entity The field data to check
     *  @return  bool true if the field has the feature that is produced by
     *      this ahjo.
     */
    function isRequiredField($Entity) {
        return soGetBool(
            $this->__Template->getColProperty($Entity->Name,
                                              DZCPT_CONTROL,
                                              DZCP_FORMULA));
    } // isRequiredField


    /** Add field to ahjo
     *  @param object dzSourceEntity $Entity The field data to check
     *  @param string $TagName Column name
     *  @param string $FieldName The widget name on the form
     *  @param mixed $Value The fields value
     *  @return bool True on success false on error
     */
    function addField($Entity, $TagName, $FieldName, $Value) {
        if ($result = $this->isRequiredField($Entity)) {

            /* Get & set the formula definition */
            $formula = $this->__Template->getColProperty(
                $Entity->Name, DZCPT_CONTROL, DZCP_FORMULA);
            $equation = $TagName."=".$formula;
            $this->__Formulas[] = $equation;
            $this->parseDepsFromFormula($TagName, $formula);

            /* Get & store number formatting definition */
            $numfmt = $this->__Template->getColProperty(
                $Entity->Name, DZCPT_STRUCT, DZCP_NUMFMT);
            if ($numfmt) {
                $dec = intval(soExtractVal($numfmt, ",", 1));
                $len = intval(soExtractVal($numfmt, ",", 2));
                $this->__Formats[$TagName] = $dec.",".$len;
            }; // if

            /* Add code that initialzes calculate fields */
            $mode = $this->__Template->getViewData(DZ_VI_MODE);
            if (($mode == DZM_BROWSE) || ($mode == DZM_EDIT))
                $this->__Template->addInitAction(DZIA_UPDATE_CALC_FIELDS);
        }; // if

        return $result;
    } // addField


    /** Get the script code
     *  Returns the script code that is needed to implement the functionality
     *  this ahjo is responsible for.
     *  @return string The script code
     */
    function getCode() {

        /* Produce first the formulas to insert into headscript */
        $result = "";
        $fcount = count($this->__Formulas);
        foreach ($this->__Formulas as $equation) {
            list($target, $formula) = split("=", $equation);
            $result .= "formula_".$target." = \"".$formula."\";\n";
        } // for

        /* Produce the dependency lists added into the head script */
        $result .= "\n// Dependecies for the fields\n";

        $dep_arr = $this->__FieldDeps->getAsArray();
        foreach ($dep_arr as $key => $val) {
            $s = $this->getDeps($key);
            $result .= "dzDep_".$key." = Array(".$s.");\n";
        } // foreach

        /* Add format array */
        $result .= "\n// Number formatting \n";
        foreach ($this->__Formats as $key => $val) {
            $result .= "dzNumFmt_".$key." = Array(".$val.");\n";
        }; // foreach

        return $result;
    } // getCode


    /** Get static script features
     * Get the other static script features that is needed to implement
     * the functionality this ahjo is responsible for
     * @return array/string List of the required features names
     */
    function getScriptFeatures() {
        return array("calculate_fields", "post_process",
                     "general_post_process");
    } // getScriptFeatures


    /** Formula dependency parser.
     *  Parses the dependencies from the given formula and add them to the
     *  dependency set of the given column.
     *  @param string $ColTag Name of the column must be updated
     *  @param string $Formula Formula to parse
     */
    function parseDepsFromFormula($ColTag, $Formula) {
        $c = 1;
        while ($col = soParseVal($Formula, SO_DOLLAR, SO_DOLLAR, $c)) {
            $dep = $this->__FieldDeps->getItem($col);
            /* This column had no dependencies yet*/
            if ($this->__FieldDeps->Error)  $dep = new soSet;

            /* Add this column as a dependant and add it to dep list */
            $dep->addItem($ColTag);
            $this->__FieldDeps->setItem($col, $dep, 1);
            $c = $c + 2;
        } //while
    } // parseDepsFromFormula


    /** Find out the dependency chain for a given field.
     *  @param string $Field The name of field which dependency chain to seek
     *  @return string The dependency chain for the given field as a string.
     *  Field names are closed in "'"-marks and separated with comma.
     */
    function getDeps($Field) {

        /* Get the set of dependencies this field has and STOP if the
         * object is not valid */
        $dep_arr = $this->__FieldDeps->getAsArray();
        $fieldDepsSet = $dep_arr[$Field];
        if (!is_object($fieldDepsSet)) return ""; // <-- EXIT

        $result = '';
        $fieldDepsArr = $fieldDepsSet->getAsArray();

        /* Iterate through all the depending fields */
        while (list ($dep_field, $none) = each ($fieldDepsArr)) {
            $result = soJoinStr($result, ",", "'$dep_field'", 1);

            /* Recursive call to find out the dependencies for the
            * current field */
            $sub_dep = $this->getDeps($dep_field);

            /* If there was any dependencies join them to the chain */
            if ($sub_dep) $result = soJoinStr($result, ",", $sub_dep, 1);
        }; // while

        return $result;
    } // getDeps

} //  dzAhjoCalculate


/** Forge that produces the validy check information
 *  @var object dzTemplate Form information. Includes tons of field
 *  information too
 *  @var object soset/string $__FieldList Field validation defines
 */
class dzAhjoValidate extends dzBaseAhjo {
    var $__Template = NULL;
    var $__FieldList;


    /*  NOTE! When copying this class, in order to handle different type
     *  of Ahjo function/purpose, update the name of the constructor to
     *  correspond the new class name.
     *  @param object dzTemplate Form template object.
     */
    function dzAhjoValidate(&$Template) {
        soDebug("dzAhjo: Create ahjo dzAhjoValidate",SOD_DET);
        $this->setTemplate($Template);
        $this->__FieldList = new soSet();
    } // constructor


    /** Check if this field is needs this ahjo.
     *  Inspects the field properties and decides whether this ahjo is needed
     *  to implement the fields features.
     *  >$Entity:dzSourceEntity The field data to check
     *  <:bool true if the field has the feature that is produced by this ahjo.
     */
    function isRequiredField($Entity) {
        return soGetBool(
            $this->__Template->getColProperty($Entity->Name,
                                              DZCPT_CONTROL,
                                              DZCP_VALIDATE));
    } // isRequiredField


    /** Add field to ahjo
     *
     *  >$Entity:dzSourceEntity The field data to check
     *  >$TagName:str   Column name
     *  >$FieldName:str   The widget name on the form
     *  >$Value:any   The fields value
     *  <:bool  true on success false on error
     */
    function addField($Entity, $TagName, $FieldName, $Value) {
        if ($this->isRequiredField($Entity)) {
            $validate_def = $this->__Template->getColProperty(
                $Entity->Name, DZCPT_CONTROL, DZCP_VALIDATE);
            /* Is rpc add the coordinates of the function */
            if (soLocateStr($validate_def, "rpc:", 1) >= 0) {
                $validate_def = completeRpcInfo($validate_def);
            } // if
            $this->__FieldList->addItem($TagName, $validate_def);

            $result = true;
        } else {
            $result = false;
        } // if

        return $result;
    } // addField


    /** Get the script code
     *  The script code that is needed to implement the functionality this
     *  ahjo is responsible for.
     *  @return string The script code
     */
    function getCode() {
        $result = "";
        $mode = $this->__Template->getViewData(DZ_VI_MODE);

        if ($mode != DZM_QUERY) {
            $validate_defs = $this->__FieldList->getAsArray();
            foreach ($validate_defs as $field_name => $function) {
                $result .= "dzValidate_".$field_name."=\"".$function."\";\n";
            } // while
        } // if

        return $result;
    } // getCode


    /** Get static script features
     *  Get the other static script features that is needed to implement
     *  the functionality this ahjo is responsible for
     *  @return array/string List of the required features names
     */
    function getScriptFeatures() {
        return array("validate_fields", "post_process",
                     "general_post_process", "rcall");
    } // getScriptFeatures

} //  dzAhjoValidate



/** Ahjo that produces the new line event. This event is triggered when
 *  the focus leaves a field that is on new row. That is row that is used
 *  to add rows to group.
 *  @param dzTemplate $__Template Reference to used template
 */
class dzAhjoNewLine extends dzBaseAhjo {
    var $__Template = NULL;
    var $__Fields;       /**soSet/array/str Fields and the required fields.
                            The key is a field name and the value is the list
                            of required fields. That should be checked by
                            script.*/
    var $__ReqFields;   /**soSet/array/str Fields that are required before
                           triggering the new line event. Key is group number */


    /*  NOTE! When copying this class, in order to handle different type
     *  of Ahjo function/purpose, update the name of the constructor to
     *  correspond the new class name.
     *  @param object dzTemplate Form template object.
     */
    function dzAhjoNewLine(&$Template) {
        soDebug("dzAhjo: Create ahjo dzAhjoNewLine",SOD_DET);
        $this->setTemplate($Template);
        $this->__Fields = new soSet();
        $this->__ReqFields = new soSet();
    } // constructor


    /** Check if this field is needs this ahjo.
     *  Inspects the field properties and decides whether this ahjo is needed
     *  to implement the fields features.
     *  >$FieldName:str   The widget name on the form
     *  >$Value:any   The fields value
     *  <:bool true if the field has the feature that is produced by this ahjo.
     */
    function isRequiredField($FieldName) {
        /* Check if this is an insert row */
        return soGetBool(soSubStr($FieldName, 0, 1) == "n");
    } // isRequiredField


    /** Add field to ahjo
     *
     *  >$Entity:dzSourceEntity The field data to check
     *  >$TagName:str   Column name
     *  >$FieldName:str   The widget name on the form
     *  >$Value:any   The fields value
     *  <:bool  true on success false on error
     */
    function addField($Entity, $TagName, $FieldName, $Value) {
        if ($this->isRequiredField($FieldName)) {
        /* Add insert line information. These lines are the last ones in the
           group/pot in edit and new modes and used to add new rows to
           database. Column can be required aswell. In JS when the focus
           is lost from a field that is type of insert field, then all
           required fields are checked. If all of them have a value then the
           insert new row event is triggered. */

            $grp_no = soExtractVal($FieldName, "_", 2);
            $required = $this->__Template->getColProperty(
                $Entity->Name, DZCPT_STRUCT, DZCP_REQUIRED);

            /* Ad the field on the list of insert fields*/
            $cols = $this->__Fields->getItem($grp_no);
            $cols[] = $FieldName;
            $this->__Fields->setItem($grp_no, $cols);

            /* Insert field into required field set aswell if needed. */
            if ($required) {
                $cols = $this->__ReqFields->getItem($grp_no);
                $cols[] = $FieldName;
                $this->__ReqFields->setItem($grp_no, $cols);
            } //if

            $result = true;
        } else {
            $result = false;
        } // if

        return $result;
    } // addField


    /** Get the script code
     *  Get the script code that is needed to implement the functionality this
     *  ahjo is responsible for.
     *  <: the script code
     */
    function getCode() {
        $result = "";
        $new_fields_arr = $this->__Fields->getAsArray();
        foreach($new_fields_arr as $grp_no => $new_fields) {
            foreach($new_fields as $field) {
                $result .= "dzNewFld_".$field." = new Array(";
                $s = "";
                $rfields = &$this->__ReqFields;
                if ($rfields->itemExists($grp_no)) {
                    $grp_req_fields = $rfields->getItem($grp_no);

                    /* The following line is a quick hack: why ReqFields
                     * does not get initialised in the first place? */
                    if (!is_array($grp_req_fields)) $grp_req_fields = array();
                    foreach ($grp_req_fields as $req_field) {
                        $s = soJoinStr($s, ",", "'".$req_field."'");
                    } // foreach ($req_fields)
                } // if
                $result .= $s.");\n";
            } // foreach ($new_fields)
        } // foreach ($new_fields_arr)

        return $result;
    } // getCode


    /** Get static script features
     * Get the other static script features that is needed to implement
     * the functionality this ahjo is responsible for
     * <:array/str  List of the required features names
     */
    function getScriptFeatures() {
        return array();
    } // getScriptFeatures
} //  dzAhjoNewLine


/** Ahjo that produces the filter group information
 *  @param dzTemplate $__Template Reference to used template
 */
class dzAhjoFilterGroup extends dzBaseAhjo {
    var $__Template = NULL;


    /*  NOTE! When copying this class, in order to handle different type
     *  of Ahjo function/purpose, update the name of the constructor to
     *  correspond the new class name.
     *  @param object dzTemplate Form template object.
     */
    function dzAhjoFilterGroup(&$Template) {
        soDebug("dzAhjo: Create ahjo dzAhjoFilterGroup",SOD_DET);
        $this->setTemplate($Template);
    } // constructor


    /** Check if this field is needs this ahjo.
     *  Inspects the field properties and decides whether this ahjo is needed
     *  to implement the fields features.
     *  >$Entity:dzSourceEntity The field data to check
     *  <:bool true if the field has the feature that is produced by this ahjo.
     */
    function isRequiredField($Entity) {
        return false;
    } // isRequiredField


    /** Add field to ahjo
     *
     *  >$Entity:dzSourceEntity The field data to check
     *  >$TagName:str   Column name
     *  >$FieldName:str   The widget name on the form
     *  >$Value:any   The fields value
     *  <:bool  true on success false on error
     */
    function addField($Entity, $TagName, $FieldName, $Value) {
        if ($this->isRequiredField($Entity)) {
            $result = true;
        } else {
            $result = false;
        } // if

        return $result;
    } // addField


    /** Get the script code
     *  Get the script code that is needed to implement the functionality this
     *  ahjo is responsible for.
     *  <: the script code
     */
    function getCode() {
//        $filter_seed_groups = $this->__Laituri->getFilterSeedGroups();
//        $filter_seed_cols = array(); /* XXX Get the real columns */

        $item_list = "";
        foreach ($filter_seed_groups as $group_name) {
            $item_list = soJoinStr($item_list, ",", "$group_name");
        } // foreach

        foreach ($filter_seed_cols as $col_name) {
            $item_list = soJoinStr($item_list, ",", "$col_name");
        } // foreach

        $item_list = "tt,ze";
        $result .= "var FilterEventSources = '$item_list';\n";
    } // getCode


    /** Get static script features
     * Get the other static script features that is needed to implement
     * the functionality this ahjo is responsible for
     * <:array/str  List of the required features names
     */
    function getScriptFeatures() {
        return array();
    } // getScriptFeatures

} //  dzAhjoFilterGroup


/** Ahjo that produces the information fields that triggers the fetch event
 *  @param dzTemplate $__Template Reference to used template
 */
class dzAhjoFetch extends dzBaseAhjo {
    var $__Template = NULL;
    var $__Fields;          /**soSet/str Name of fields that triggers
                                         the event */

    /*  NOTE! When copying this class, in order to handle different type
     *  of Ahjo function/purpose, update the name of the constructor to
     *  correspond the new class name.
     *  @param object dzTemplate Form template object.
     */
    function dzAhjoFetch(&$Template) {
        soDebug("dzAhjo: Create ahjo dzAhjoFetch",SOD_DET);
        $this->setTemplate($Template);
        $this->__Fields = new soSet();
    } // constructor


    /** Check if this field is required this ahjo.
     *  Inspects the field properties and decides whether this ahjo is needed
     *  to implement the fields features.
     *  >$Entity:dzSourceEntity The field data to check
     *  <:bool true if the field has the feature that is produced by this ahjo.
     */
    function isRequiredField($Entity) {
        return soGetBool(
            $this->__Template->getColProperty($Entity->Name,
                                              DZCPT_STRUCT,
                                              DZCP_FETCHING));
    } // isRequiredField


    /** Add field to ahjo
     *
     *  >$Entity:dzSourceEntity The field data to check
     *  >$TagName:str   Column name
     *  >$FieldName:str   The widget name on the form
     *  >$Value:any   The fields value
     *  <:bool  true on success false on error
     */
    function addField($Entity, $TagName, $FieldName, $Value) {
        if ($this->isRequiredField($Entity)) {
            $fetch_def = $this->__Template->getColProperty(
                $Entity->Name, DZCPT_STRUCT, DZCP_FETCHING);
            $fetch_keys = soExplode(soExtractVal($fetch_def, ",", 1), "+");
            foreach ($fetch_keys as $key) {
                    if ($key[0] == SO_DOLLAR) {
                        $real_name = soSubStr($key, 1, strlen($key) -1);
                        $this->__Fields->setItem($real_name, "");
                    } // if
            } // foreach
            $result = 1;
        } else {
            $result = 0;
        } // else if

        return $result;
    } // addField


    /** Get the script code
     *  Get the script code that is needed to implement the functionality this
     *  ahjo is responsible for.
     *  <: the script code
     */
    function getCode() {
        $result = "";
        $mode = $this->__Template->getViewData(DZ_VI_MODE);

        if ($mode != DZM_QUERY) {
            $field_list = $this->__Fields->getKeys();
            foreach ($field_list as $field) {
                /* No periods allowed in the field names.*/
                $field = soSwapStr($field, ".", DZ_DR_STR);
                $result .= "dzFetch_$field=1;\n";
            } // foreach
            $result .= "\n";
        } // if

        return $result;
    } // getCode


    /** Get static script features
     * Get the other static script features that is needed to implement
     * the functionality this ahjo is responsible for
     * <:array/str  List of the required features names
     */
    function getScriptFeatures() {
        return array();
    } // getScriptFeatures

} //  dzAhjoFetch




/** Ahjo that produces the list of readonly fields
 *  @param dzTemplate $__Template Reference to used template
 */
class dzAhjoReadOnly extends dzBaseAhjo {
    var $__Template = NULL;
    var $__FieldList;       /**array/str list of fields that are locked */
    var $__LockedColList;   /**array/str list of columns that are locked
                                         The column tags are stored. */
    var $__ColList;         /**soset/array/str list of columns that might by
                               locked. Set key is column tag and the value is array
                               that holds the fieldnames */

    /*  NOTE! When copying this class, in order to handle different type
     *  of Ahjo function/purpose, update the name of the constructor to
     *  correspond the new class name.
     *  @param object dzTemplate Form template object.
     */
    function dzAhjoReadOnly(&$Template) {
        soDebug("dzAhjo: Create ahjo dzAhjoReadOnly",SOD_DET);
        $this->setTemplate($Template);
        $this->__FieldList = array();
        $this->__LockedColList = array();
        $this->__ColList = new soSet();
    } // constructor


    /** Add field to ahjo
     *  >$Entity:dzSourceEntity The field data to check
     *  >$TagName:str   Column name
     *  >$FieldName:str   The widget name on the form
     *  >$Value:any   The fields value
     *  <:bool  true on success false on error
     */
    function addField($Entity, $TagName, $FieldName, $Value) {
        /* Check if the field shoud be locked */
        $field = $this->__Template->getColProperty(
            $Entity->Name, DZCPT_CONTROL, DZCP_LOCKFIELD);
        /* Check the condition. '*' is a wild card it matches anything
           but an empty value. '**' includes also an empty value */
        if ($field && ($field == $Value)) {
            $this->__FieldList[] = $FieldName;
        } else {
            if (($field == "**") ||(($field == "*") && trim($Value))) {
                $this->__FieldList[] = $FieldName;
            };
        }; // else if

        /* Check if the column shoud be locked */
        $col = $this->__Template->getColProperty(
            $Entity->Name, DZCPT_CONTROL, DZCP_LOCKCOL);
        if ($col) {
            /* insert this field into field list. */
            $field_list = $this->__ColList->getItem($TagName);
            $field_list[] = $FieldName;
            $this->__ColList->setItem($TagName, $field_list);

            /* Check the condition. '*' is a wild card it matches anything
               but an empty value. '**' includes also an empty value */
            if ($col == $Value){
                $this->__LockedColList[] = $TagName;
            } else if (($col == "**") ||
                    (($col == "*") && trim($Value)))
                $this->__LockedColList[] = $TagName;
            } // if

        return $result;
    } // addField


    /** Get the script code
     *  Get the script code that is needed to implement the functionality this
     *  ahjo is responsible for.
     *  <: the script code
     */
    function getCode() {
        /* First add single readonly fields */
        $items = "";
        foreach ($this->__FieldList as $field_name) {
            $items = soJoinStr($items, ",", "'$field_name'");
        } // foreach

        /* Then add whole column lists if column is readonly */
        foreach ($this->__LockedColList as $locked_col_tag) {
            $field_list = $this->__ColList->getItem($locked_col_tag);
            if (is_array($field_list)) {
                foreach ($field_list as $field_name) {
                    $items = soJoinStr($items, ",", "'$field_name'");
                } // foreach
            }
        } // foreach

        $code = "dzreadonly = new Array($items);\n";

        return $code;
    } // getCode


    /** Get static script features
     *  Get the other static script features that is needed to implement
     *  the functionality this ahjo is responsible for
     *  <:array/str  List of the required features names
     */
    function getScriptFeatures() {
        $result = array('readonly');

        return $result;
    } // getScriptFeatures

} //  dzAhjoReadOnly

?>
